/*****************************
 *@file: BaseBullet
 *@author: 陈吕唐
 *@desc: 远程子弹基类
 *@date: 2024-03-18	15:15
 *****************************/
import { _decorator, Collider2D, Component, Contact2DType, IPhysics2DContact, math, NodePool, RigidBody2D, v2, warn } from 'cc';
import { BaseCharacter } from '../BaseCharacter';
import { BuffController } from '../buff/BuffController';
import IBaseBuffDTO from '../buff/IBaseBuffDTO';
import GameUtils from '../GameUtils';
import { PhysicsEnum } from '../PhysicsEnum';
import IBaseBulletValue from './IBaseBulletValue';
const { ccclass, property, disallowMultiple } = _decorator;

@ccclass('BaseBullet')
@disallowMultiple(true)
export class BaseBullet extends Component {
    /****************************************************************************************************************
     *Readonly 常量
     ****************************************************************************************************************/
    /****************************************************************************************************************
     *Property 定义变量
     ****************************************************************************************************************/
    /**
     * 对象池
     */
    private pool: NodePool = undefined!;

    /**
     * 子弹伤害数据
     */
    public value: IBaseBulletValue = undefined!;

    /**
     * 子弹来源
     */
    public source: BaseCharacter = undefined!;

    /**
     * 子弹携带的buff数据(可为空)
     */
    public buff: IBaseBuffDTO = undefined!;
    /***************************************************************
    *PropertyUI 引用的控件
    ***************************************************************/
    @property({ group: { name: 'BOX2D', id: '1' }, type: RigidBody2D, tooltip: `子弹刚体` })
    private body: RigidBody2D = undefined!;

    @property({ group: { name: 'BOX2D', id: '1' }, type: Collider2D, tooltip: `当前碰撞实体形状(默认从当前节点查找)` })
    private collider: Collider2D = null;
    /****************************************************************************************************************
     * Lifecycle 生命周期相关方法
     ****************************************************************************************************************/
    protected onLoad(): void {
        if (!this.body) {
            this.body = this.getComponent(RigidBody2D);
        }

        let colliders = this.node.getComponents(Collider2D);
        if (!this.collider) {
            this.collider = colliders.find((c) => c.tag === PhysicsEnum.ColliderTagGroup.BODY);
        }

        this.addBodyListener(this.collider);
    }
    /****************************************************************************************************************
     * Public 公有方法
     ****************************************************************************************************************/
    /**
     * 设置子弹速度
     * @param v 方向向量
     */
    public setLinearVelocity(v: math.Vec2): void {
        /**
         * 设置向量长度,即速度大小
         */
        let length: number = 10;
        /**
         * 设置子弹方向
         */
        v.normalize();
        v.multiplyScalar(length);
        this.body.linearVelocity = v;

        /**
         * 设置子弹旋转
         */
        let angle = -v.signAngle(v2(1, 0)) / Math.PI * 180;
        this.node.setRotationFromEuler(0, 0, angle);

        this.scheduleOnce(() => {
            this.recycle();
        }, 10);

    }
    /*********************************************
     * 对象池
     *********************************************/
    /**
     * 对象池回收时调用
     */
    public unuse() {
        this.pool = undefined!;
        this.source = undefined!;
        this.buff = undefined!;
        this.value = undefined!;
    }

    /**
     * 对象池重新启用时调用
     */
    public reuse(pool: NodePool) {
        this.pool = pool;
    }
    /*********************************************
     * 碰撞回调
     *********************************************/
    /**
     * 碰撞到实体时候调用
     * @param selfCollider 
     * @param otherCollider 
     * @param contact 
     */
    protected onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        switch (otherCollider.group) {
            case PhysicsEnum.PhysicsGroup.BORDER:
                this.onBorder();
                break;
            default:
                break;
        }

        let character = GameUtils.getCharacterByCollider(otherCollider);
        if (character) {
            this.onHit(character, contact);
        }
    }

    /**
     * 碰撞到实体分开时候调用
     * @param selfCollider 
     * @param otherCollider 
     * @param contact 
     */
    protected onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {

    }


    /**
     * 撞击到对象
     * @param character 
     */
    protected onHit(character: BaseCharacter, contact: IPhysics2DContact | null = null) {

    }

    /**
     * 子弹对单位造成伤害
     * @param character 被攻击的战斗单位
     * @param value 伤害数据
     */
    protected damage(character: BaseCharacter, value: IBaseBulletValue = this.value): void {
        if (!character.gameIng) {
            return;
        }
        character.takeDamage(value, this.source);

        if (this.buff) {
            //对单位施加状态
            //FIXME: 这里添加BUFF控制组件  不优雅
            let control = character.getComponent(BuffController);
            if (!control) {
                control = character.addComponent(BuffController);
            }
            control.applyBuff(this.buff);
        }
    }

    /**
     * 碰撞到游戏边界
     */
    protected onBorder() {
        this.recycle();
    }
    /****************************************************************************************************************
     * private 私有方法
     ****************************************************************************************************************/
    /**
     * 添加碰撞实体监听
     * @param collider 
     * @returns 
     */
    private addBodyListener(collider: Collider2D = this.collider) {
        if (!collider) {
            warn('collider is null');
            return;
        }


        if (!collider.hasEventListener(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this)) {
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        }
        if (!collider.hasEventListener(Contact2DType.END_CONTACT, this.onEndContact, this)) {
            collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
        }
    }
    /**
     * 回收子弹
     */
    protected recycle(): void {
        this.scheduleOnce(() => {
            if (this.pool) {
                this.pool.put(this.node);
            } else {
                this.node.removeFromParent();
            }
        }, 0);
    }
    /****************************************************************************************************************
     * Property Get && Set 属性的 get && set 函数
     ****************************************************************************************************************/
}


